package site.jlopen.service.imp;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.util.IOUtils;

import site.jlopen.assets.oss.AwsOssConfig;
import site.jlopen.assets.oss.OssAutoCloseableClient;
import site.jlopen.entity.BaseResponse;
import site.jlopen.entity.file.FileUploadRes;
import site.jlopen.service.intf.oss.OssService;
import site.jlopen.utils.StringUtil;
import site.jlopen.utils.id.Seq;

@Service
public class OssServiceImpl implements OssService {
	private static Logger logger = LoggerFactory.getLogger(OssServiceImpl.class);

	/*private final OssClientFactory ossClientFactory;
	
	public OssServiceImpl(OssClientFactory ossClientFactory) {
		this.ossClientFactory = ossClientFactory;
	}*/
	
	private OssAutoCloseableClient getOssClient(AwsOssConfig config) {
        return OssAutoCloseableClient.createClient(config);
    }

	@Override
    public BaseResponse<String> checkBucketExists(AwsOssConfig awsOssConfig, String bucketName) {
        try (OssAutoCloseableClient s3Client = getOssClient(buildAwsOssConfig(awsOssConfig))) {
            //try to check bucket exist
            logger.info("start check bucket");
            if (!s3Client.doesBucketExistV2(bucketName)) {
                //throw SdkBaseException.of(DatasourceErrorCode.DATA_SOURCE_BUCKET_NOT_EXIST);
                return new BaseResponse<String>().error("BUCKET 不存在");
            }
            return new BaseResponse<String>().success("succ");
        } catch (AmazonS3Exception e) {
            logger.error("There was an error response from S3. This might indicate that the credentials are invalid.");
            logger.error("Error Message:    " + e.getErrorResponseXml());
            if ("PermanentRedirect".equalsIgnoreCase(e.getErrorCode())) {
                //throw SdkBaseException.of(DatasourceErrorCode.DATA_SOURCE_BUCKET_NOT_MATCH_ENDPOINT, e);
                return new BaseResponse<String>().error("BUCKET 与 ENDPOINT 不匹配");
            }
            if ("InvalidAccessKeyId".equalsIgnoreCase(e.getErrorCode()) || "SignatureDoesNotMatch".equalsIgnoreCase(e.getErrorCode())) {
                //throw SdkBaseException.of(DatasourceErrorCode.DATA_SOURCE_CREDENTIALS_INVALID, e);
                return new BaseResponse<String>().error("认证凭证错误");
            }
            if (HttpStatus.BAD_REQUEST.value() == e.getStatusCode()) {
                //throw SdkBaseException.of(DatasourceErrorCode.DATA_SOURCE_ENDPOINT_API_PORT_ERROR, e);
                return new BaseResponse<String>().error("ENDPOINT API 请求失败");
            }
            //throw SdkBaseException.of(DatasourceErrorCode.DATASOURCE_UNKNOWN_EXCEPTION, e);
            return new BaseResponse<String>().error("UNKNOWN 错误");
        } catch (Exception e) {
            logger.error("Unknown exception", e);
            //throw SdkBaseException.of(DatasourceErrorCode.DATA_SOURCE_CREATE_FAIL, e);
            return new BaseResponse<String>().error("数据源注册失败");
        }
    }


    @Override
    public boolean checkObjectExists(AwsOssConfig awsOssConfig, String bucketName, String objectKey) {
        try (OssAutoCloseableClient s3Client = getOssClient(buildAwsOssConfig(awsOssConfig))) {
            //try to check bucket exist
            logger.info("start check objectKey");
            return s3Client.doesObjectExist(bucketName, objectKey);
        } catch (Exception e) {
            logger.error("Unknown exception", e);
            return false;
        }
    }


    private AwsOssConfig buildAwsOssConfig(AwsOssConfig awsOssConfig) {
        return AwsOssConfig.builder()
                .accessKeyId(awsOssConfig.getAccessKeyId())
                .secretAccessKey(awsOssConfig.getSecretAccessKey())
                .endpoint(awsOssConfig.getEndpoint())
                .build();
    }

	@Override
	public BaseResponse<FileUploadRes> upload(MultipartFile file, AwsOssConfig ossConfig, String bucket, 
			String prefix,String fileDir, String fileName) {
		ByteArrayInputStream inputS = null;
		try {
			InputStream input = file.getInputStream();
			inputS = new ByteArrayInputStream(IOUtils.toByteArray(input));
		} catch (IOException e) {
    		return new BaseResponse<FileUploadRes>().error("读取上传失败");
		}
		fileDir = prefix + "/" + fileDir;
		ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(file.getContentType());
        metadata.setContentLength(file.getSize());
        try (OssAutoCloseableClient s3Client = getOssClient(buildAwsOssConfig(ossConfig))) {
            if(StringUtil.isEmpty(fileName)) {
    			fileName = String.format("%s_%s", Seq.getId(Seq.uploadSeqType), file.getOriginalFilename());
            }
            PutObjectResult pres =  s3Client.putObject(bucket, fileDir + "/" + fileName, inputS, metadata);
            logger.info("pres:{}", pres);
            String url = ossConfig.getEndpoint() + "/" + bucket + "/" + fileDir + "/" + fileName;
            FileUploadRes res = FileUploadRes.success(file.getOriginalFilename(), fileName, fileDir + "/" + fileName, url, file.getSize());
            S3Object s3Obj = s3Client.getObject(bucket, fileDir + "/" + fileName);
            logger.info("s3Obj:{}", s3Obj);
    		return new BaseResponse<FileUploadRes>().success("上传成功").setData(res);
        } catch (SdkClientException e) {
            logger.error("Sdk Client exception", e);
    		return new BaseResponse<FileUploadRes>().error("上传失败");
        } catch (Exception e) {
            logger.error("Unknown exception", e);
    		return new BaseResponse<FileUploadRes>().error("上传失败");
        }
	}
}
